//-----------------------------------------------------------------------------
//
// @file	Camera.h
// @brief	File with all camera data
// @author	Vinod Melapudi
// @date	20Feb2010
//
//-----------------------------------------------------------------------------

#include "Camera.h"
#include "Quaternion.h"

#include "OpenGLRender.h"

Camera::Camera()
{
	Reset();
}

void Camera::Reset()
{
	m_fov		= 60.f;
	m_near_z	= 0.1f;
	m_far_z		= 10240.f;

	m_pos.set( 0.f, 0.f, 1.f );
	m_look_at.set( 0.f, 0.f, 0.f );
	m_up_vec.set( 0.f, 1.f, 0.f );

	m_pan_rate	= 0.1f;
	m_zoom_rate = 0.1f;
}

void Camera::Pan( float x, float y )
{
	Vector3 zVec = (m_look_at - m_pos).normalize();
	Vector3 xVec = m_up_vec.normalize() % zVec;
	Vector3 yVec = zVec % xVec;
	Vector3 pan = (xVec * x - yVec * y) * m_pan_rate;
	m_pos += pan;
	m_look_at += pan;
}

void Camera::Zoom( float z )
{
	Vector3 camVec = m_look_at - m_pos;
	Vector3 zoom = camVec.normalize() * z * m_zoom_rate;
	m_pos += zoom;
	m_look_at += zoom;
}

// Rotate camera based on mouse input
void Camera::Rotate( float mouse_x, float mouse_y )
{
	Vector3 zCamVec = (m_pos - m_look_at).normalize();
	Vector3 xCamVec = Vector3(0,1,0) % zCamVec;
	Vector3 yCamVec = zCamVec % xCamVec;

	Vector3 mouseVec = xCamVec.normalize() * mouse_x + yCamVec.normalize() * mouse_y;
	Vector3 axis = mouseVec.normalize() % zCamVec;

	float angle = Vector2(mouse_x,mouse_y).norm() * PI / 360;

	Rotate( axis, angle );
}

// Rotate camera around axis with angle
void Camera::Rotate( Vector3 axis, float angle )
{
	Quaternion q;
	q.FromAngleAxis( axis.normalize(), angle );

	Vector3 camVec = (m_pos - m_look_at).normalize();
	Vector3 newCamVec = q.Rotate( camVec );

	float dist = (m_pos - m_look_at).norm();
	m_pos = m_look_at + newCamVec * dist;
}

void Camera::glPerspective( float screenWidth, float screenHeight )
{
	gluPerspective( m_fov, screenWidth/screenHeight, m_near_z, m_far_z );
}

void Camera::glLookAt()
{
	gluLookAt(	m_pos.x, m_pos.y, m_pos.z,
				m_look_at.x, m_look_at.y, m_look_at.z,
				m_up_vec.x, m_up_vec.y, m_up_vec.z );
}
